<template>
  <div class="er-tools">
    <!-- 顶部公告栏 -->
    <div class="announcement-bar">
      <i class="el-icon-bell"></i>
      <div class="announcement-content">
        <div class="scroll-text">
          <span v-for="(notice, index) in announcements" :key="index">
            {{ notice }} &nbsp;&nbsp;&nbsp;&nbsp;
          </span>
        </div>
      </div>
    </div>

    <!-- 主要功能区域 -->
    <div class="main-container">
      <!-- 左侧面板 -->
      <div class="left-panel">
        <div class="style-control">
          <h3>图形样式</h3>
          <div class="style-options">
            <div class="color-picker">
              <span>图形颜色</span>
              <input type="color" v-model="shapeColor" @change="updateShapeStyle">
            </div>
            <div class="color-picker">
              <span>线条颜色</span>
              <input type="color" v-model="lineColor" @change="updateLineStyle">
            </div>
          </div>
        </div>
        <div class="layout-control">
          <h3>布局类型</h3>
          <div class="layout-options">
            <el-select v-model="layoutType" @change="applyLayout">
              <el-option label="经典布局" value="classic"></el-option>
              <el-option label="树状布局" value="tree"></el-option>
              <el-option label="星芒布局" value="radial"></el-option>
            </el-select>
            <el-button size="small" @click="autoLayout">自动布局</el-button>
          </div>
        </div>
        <div class="display-mode">
          <h3>显示模式</h3>
          <div class="mode-options">
            <label>
              <input 
                type="radio" 
                v-model="displayMode" 
                value="full" 
                name="displayMode"
              > 完整模式 (名称+注释+类型)
            </label>
            <label>
              <input 
                type="radio" 
                v-model="displayMode" 
                value="simple" 
                name="displayMode"
              > 简洁模式 (名称+类型)
            </label>
          </div>
        </div>
        <div class="tools-section">
          <h3>基础图形</h3>
          <div class="shapes-container">
            <div
              v-for="shape in shapes"
              :key="shape.type"
              class="shape-item"
              draggable="true"
              @dragstart="onShapeDragStart($event, shape)"
            >
              <div :class="['shape-preview', shape.type]"></div>
              <span>{{ shape.label }}</span>
            </div>
          </div>
        </div>
        <div class="sql-input">
          <h3>SQL 转换</h3>
          <textarea 
            v-model="sqlInput"
            placeholder="请输入 CREATE TABLE SQL 语句..."
            rows="10"
          ></textarea>
          <button @click="generateER" class="generate-btn">生成 ER 图</button>
        </div>
        <div class="style-control">
          <h3>连线样式</h3>
          <el-radio-group v-model="lineStyle" @change="updateLineStyle">
            <el-radio label="straight">直线</el-radio>
            <el-radio label="smooth">曲线</el-radio>
            <el-radio label="manhattan">折线</el-radio>
          </el-radio-group>
        </div>
      </div>

      <!-- 中间画布 -->
      <div class="canvas-container" ref="container" @dragover.prevent @drop="onShapeDrop" tabindex="0">
      </div>

      <!-- 右侧面板 -->
      <div class="right-panel">
        <h3>导出功能</h3>
        <div class="export-options">
          <button class="export-btn" @click="exportAsImage('png')">
            <i class="el-icon-picture"></i>
            导出为PNG
          </button>
          <button class="export-btn" @click="exportAsImage('jpeg')">
            <i class="el-icon-picture-outline"></i>
            导出为JPEG
          </button>
          <button class="export-btn" @click="exportAsJson">
            <i class="el-icon-document"></i>
            导出为JSON
          </button>
          <button class="export-btn" @click="exportAsSvg">
            <i class="el-icon-picture-outline-round"></i>
            导出为SVG
          </button>
        </div>
      </div>
    </div>

    <!-- 底部版权信息 -->
    <footer class="copyright-bar">
      <div class="copyright-left">
        <span class="logo">ETNOR-API</span>
        <span class="version">v1.0.0</span>
      </div>
      <div class="copyright-center">
        © {{ currentYear }} ETNOR-API. All Rights Reserved.
      </div>
      <div class="copyright-right">
        <a href="#">使用文档</a>
        <a href="#">问题反馈</a>
        <a href="#">关于我们</a>
      </div>
    </footer>
  </div>
</template>

<script>
import { Graph, Shape, NodeTool } from '@antv/x6'
import { DagreLayout } from '@antv/layout'
// 引入导出相关模块
import { Export } from '@antv/x6-plugin-export'

// 注册自定义编辑工具
Graph.registerNodeTool('edit-text', {
  name: 'edit-text',
  config: {
    trigger: 'dblclick',
  },
  handler: {
    init() {
      this.editor = document.createElement('div')
      this.editor.className = 'node-text-editor'
      this.editor.contentEditable = 'true'
      this.editor.style.position = 'absolute'
      this.editor.style.zIndex = '999'
      this.editor.style.background = '#fff'
      this.editor.style.border = '1px solid #1890ff'
      this.editor.style.padding = '4px'
      this.editor.style.minWidth = '50px'
      this.editor.style.minHeight = '20px'
      this.editor.style.outline = 'none'
      this.editor.style.boxShadow = '0 2px 6px rgba(0,0,0,0.1)'
    },
    enable() {
      const cell = this.cell
      const text = cell.attr('label/text')
      
      const bbox = cell.getBBox()
      this.editor.style.left = `${bbox.x}px`
      this.editor.style.top = `${bbox.y}px`
      this.editor.style.width = `${bbox.width}px`
      this.editor.style.height = `${bbox.height}px`
      this.editor.innerText = text
      
      this.graph.container.appendChild(this.editor)
      this.editor.focus()
      
      document.execCommand('selectAll', false, null)
      
      this.editor.addEventListener('blur', this.onBlur.bind(this))
      this.editor.addEventListener('keydown', this.onKeyDown.bind(this))
    },
    disable() {
      if (this.editor && this.editor.parentNode) {
        this.editor.parentNode.removeChild(this.editor)
      }
    },
    onBlur() {
      const text = this.editor.innerText.trim()
      if (text) {
        this.cell.attr('label/text', text)
      }
      this.disable()
    },
    onKeyDown(e) {
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault()
        this.editor.blur()
      }
      if (e.key === 'Escape') {
        this.disable()
      }
    },
  },
})

export default {
  name: 'ERTools',
  data() {
    return {
      graph: null,
      sqlInput: '',
      displayMode: 'full',
      shapes: [
        { type: 'er-entity', label: '实体' },
        { type: 'er-attribute', label: '属性' },
        { type: 'er-key-attribute', label: '主键' },
        { type: 'er-relationship', label: '关系' }
      ],
      announcements: [
        '欢迎使用ER图设计工具！',
        '新功能：支持导出多种格式图片',
        '提示：双击节点可以直接编辑文本',
        '快捷键：按Delete键可删除选中的节点'
      ],
      shapeColor: '#ffffff',
      lineColor: '#000000',
      layoutType: 'classic',
      currentYear: new Date().getFullYear(),
      selectedCells: [], // 当前选中的图形
      isEditing: false, // 是否正在编辑
      lineStyle: 'manhattan', // 默认折线
      currentTableInfo: null, // 保存当前表信息
      isLoading: false
    }
  },
  mounted() {
    this.initGraph()
    // 添加键盘事件监听
    window.addEventListener('keydown', this.handleKeyDown)
  },
  methods: {
    initGraph() {
      if (this.graph) {
        this.clearGraph()
      }

      this.graph = new Graph({
        container: this.$refs.container,
        width: '100%',
        height: '100%',
        grid: {
          type: 'mesh',
          size: 10,
          visible: true
        },
        selecting: {
          enabled: true,
          multiple: true,
          rubberband: true,
          showNodeSelectionBox: false,
          strict: true
        },
        resizing: {
          enabled: true,
          minWidth: 100,
          minHeight: 40,
          maxWidth: 500,
          maxHeight: 300,
          orthogonal: true,
          restricted: true,
          preserveAspectRatio: false
        },
        interacting: {
          nodeMovable: true,
          magnetConnectable: true
        }
      })

      // 注册选择事件
      this.graph.on('node:selected', ({ node }) => {
        // 添加选择框和调整大小工具
        node.addTools([
          {
            name: 'boundary',
            args: {
              padding: 4,
              attrs: {
                fill: 'none',
                stroke: '#1890ff',
                'stroke-width': 1
              }
            }
          },
          {
            name: 'resize',
            args: {
              minWidth: 100,
              minHeight: 40,
              maxWidth: 500,
              maxHeight: 300,
              vertices: ['top-left', 'top-right', 'bottom-left', 'bottom-right',
                        'top', 'right', 'bottom', 'left'],
              attrs: {
                'circle': {
                  r: 4,
                  fill: '#fff',
                  stroke: '#1890ff',
                  'stroke-width': 1,
                  cursor: 'pointer'
                }
              }
            }
          }
        ])
      })

      this.graph.on('node:unselected', ({ node }) => {
        node.removeTools()
      })

      // 调整大小时更新连接线
      this.graph.on('node:resize', ({ node }) => {
        this.graph.getConnectedEdges(node).forEach(edge => {
          edge.updateConnection()
        })
      })

      // 注册实体节点
      Graph.registerNode('er-entity', {
        inherit: 'rect',
        width: 120,
        height: 50,
        attrs: {
          body: {
            fill: '#fff',
            stroke: '#000',
            strokeWidth: 2,
          },
          label: {
            fontSize: 14,
            fill: '#000',
            fontWeight: 'bold',
          }
        },
        tools: [
          {
            name: 'edit-text',
            args: {
              attrs: {
                backgroundColor: '#fff',
              },
            },
          },
        ],
      })

      // 注册属性节点
      Graph.registerNode('er-attribute', {
        inherit: 'ellipse',
        width: 100,
        height: 40,
        attrs: {
          body: {
            fill: '#fff',
            stroke: '#000',
            strokeWidth: 1,
          },
          label: {
            fontSize: 12,
            fill: '#000',
          }
        },
        tools: [
          {
            name: 'edit-text',
            args: {
              attrs: {
                backgroundColor: '#fff',
              },
            },
          },
        ],
      })

      // 注册主键属性节点
      Graph.registerNode('er-key-attribute', {
        inherit: 'er-attribute',
        attrs: {
          body: {
            strokeWidth: 2,
          },
          label: {
            fontWeight: 'bold',
            textDecoration: 'underline',
            text: '主键',
            editable: true
          }
        },
      })

      // 注册关系节点
      Graph.registerNode('er-relationship', {
        inherit: 'polygon',
        width: 100,
        height: 50,
        attrs: {
          body: {
            fill: '#fff',
            stroke: '#000',
            strokeWidth: 1,
            refPoints: '0,10 10,0 20,10 10,20',
          },
          label: {
            fontSize: 12,
            fill: '#000',
            text: '关系',
            editable: true
          }
        },
      })

      // 注册导出插件
      this.graph.use(new Export())

      // 监听选择事件
      this.graph.on('cell:selected', ({ cell }) => {
        this.selectedCells.push(cell)
        this.updateSelectionStyle()
      })

      this.graph.on('cell:unselected', ({ cell }) => {
        this.selectedCells = this.selectedCells.filter(c => c.id !== cell.id)
        this.updateSelectionStyle()
      })

      // 监听双击事件
      this.graph.on('cell:dblclick', ({ cell, e }) => {
        if (cell.isNode()) {
          this.startEditing(cell, e)
        }
      })

      // 监听键盘事件
      this.graph.bindKey(['delete', 'backspace'], () => {
        if (!this.isEditing && this.selectedCells.length > 0) {
          this.graph.removeCells(this.selectedCells)
          this.selectedCells = []
        }
      })

      // 监听画布点击事件，取消选择
      this.graph.on('blank:click', () => {
        this.graph.cleanSelection()
        this.selectedCells = []
      })

      // 初始化时给容器焦点
      this.$nextTick(() => {
        this.$refs.container.focus()
      })

      this.graph.enablePanning()
      this.graph.enableMouseWheel()
    },

    onShapeDragStart(e, shape) {
      e.dataTransfer.setData('shape-type', shape.type)
    },

    onShapeDrop(e) {
      const shapeType = e.dataTransfer.getData('shape-type')
      const { x, y } = this.graph.clientToGraph({
        x: e.clientX,
        y: e.clientY,
      })

      this.graph.addNode({
        shape: shapeType,
        x,
        y,
        attrs: {
          label: {
            text: this.shapes.find(s => s.type === shapeType)?.label || '新节点'
          }
        }
      })
    },

    // SQL解析方法
    parseSql(sql) {
      try {
        // 提取表名
        const tableNameMatch = sql.match(/CREATE\s+TABLE\s+`([^`]+)`/i)
        if (!tableNameMatch) return null
        const tableName = tableNameMatch[1]

        // 提取字段定义部分
        let fieldsStr = sql.substring(
          sql.indexOf('(') + 1,
          sql.lastIndexOf(')')
        )

        // 分割字段定义
        const fieldDefinitions = []
        let currentField = ''
        let inParentheses = 0
        let inQuotes = false

        for (let char of fieldsStr) {
          if (char === '`') inQuotes = !inQuotes
          if (!inQuotes) {
            if (char === '(') inParentheses++
            if (char === ')') inParentheses--
          }

          if (char === ',' && inParentheses === 0 && !inQuotes) {
            if (currentField.trim()) fieldDefinitions.push(currentField.trim())
            currentField = ''
          } else {
            currentField += char
          }
        }
        if (currentField.trim()) fieldDefinitions.push(currentField.trim())

        // 解析字段
        const columns = []
        const indexes = []

        fieldDefinitions.forEach(def => {
          // 处理主键定义
          if (def.toUpperCase().includes('PRIMARY KEY')) {
            const pkMatch = def.match(/PRIMARY\s+KEY\s*\(`([^`]+)`\)/i)
            if (pkMatch) {
              const pkColumn = pkMatch[1]
              // 标记主键字段
              columns.forEach(col => {
                if (col.name === pkColumn) {
                  col.isPrimaryKey = true
                }
              })
            }
            return
          }

          // 处理索引定义
          if (def.toUpperCase().includes('KEY') || def.toUpperCase().includes('INDEX')) {
            // 收集索引信息但不创建节点
            const indexMatch = def.match(/(?:UNIQUE\s+)?KEY\s+`([^`]+)`\s*\(`([^`]+)`(?:\s*,\s*`([^`]+)`)*\)/i)
            if (indexMatch) {
              indexes.push({
                name: indexMatch[1],
                columns: def.match(/`([^`]+)`/g).map(col => col.replace(/`/g, '')),
                isUnique: def.toUpperCase().includes('UNIQUE'),
                comment: def.includes('COMMENT') ? def.match(/COMMENT\s+'([^']+)'/)[1] : ''
              })
            }
            return
          }

          // 处理普通字段
          const fieldMatch = def.match(/`([^`]+)`\s+([^\s]+)/)
          if (fieldMatch) {
            const name = fieldMatch[1]
            const type = fieldMatch[2]
            
            // 提取注释
            const commentMatch = def.match(/COMMENT\s+'([^']+)'/)
            const comment = commentMatch ? commentMatch[1] : ''
            
            // 判断是否可空
            const nullable = !def.toUpperCase().includes('NOT NULL')
            
            // 提取默认值
            const defaultMatch = def.match(/DEFAULT\s+([^\s,]+)/)
            const defaultValue = defaultMatch ? defaultMatch[1] : null
            
            // 判断是否自增
            const isAutoIncrement = def.toUpperCase().includes('AUTO_INCREMENT')

            columns.push({
              name,
              type,
              comment,
              nullable,
              defaultValue,
              isAutoIncrement,
              isPrimaryKey: false
            })
          }
        })

        return {
          tableName,
          columns,
          indexes
        }
      } catch (error) {
        console.error('SQL解析错误:', error)
        return null
      }
    },

    createEntityWithAttributes(table, x, y) {
      // 创建实体节点
      const entity = this.graph.addNode({
        shape: 'er-entity',
        x,
        y,
        label: table.name,
      })

      const fields = table.fields
      const totalFields = fields.length
      
      // 计算布局参数
      const startAngle = -Math.PI / 2  // 从正上方开始
      const radius = Math.max(200, 100 + totalFields * 20)  // 根据字段数量动态调整半径
      const angleStep = (2 * Math.PI) / totalFields  // 平均分配角度
      
      // 为每个字段创建属性节点
      fields.forEach((field, index) => {
        // 计算位置，使用余弦和正弦函数确定 x 和 y 坐标
        const angle = startAngle + angleStep * index
        
        // 使用三角函数计算位置，注意要错开不同层级的属性
        let layerMultiplier = 1
        if (field.isPrimaryKey) {
          layerMultiplier = 0.8  // 主键放在内层
        } else if (field.isForeignKey) {
          layerMultiplier = 1.2  // 外键放在外层
        }
        
        const currentRadius = radius * layerMultiplier
        const attrX = x + currentRadius * Math.cos(angle)
        const attrY = y + currentRadius * Math.sin(angle)

        // 根据显示模式构造属性标签
        let attributeLabel = this.formatAttributeLabel(field)

        // 创建属性节点
        const attribute = this.graph.addNode({
          shape: field.isPrimaryKey ? 'er-key-attribute' : 'er-attribute',
          x: attrX,
          y: attrY,
          width: this.displayMode === 'full' ? 160 : 120,
          height: this.displayMode === 'full' ? 60 : 40,
          attrs: {
            body: {
              fill: '#fff',
              stroke: '#000',
              strokeWidth: field.isPrimaryKey ? 2 : 1,
            },
            label: {
              text: attributeLabel,
              fontSize: 12,
              fill: '#000',
              fontWeight: field.isPrimaryKey ? 'bold' : 'normal',
              textWrap: {
                width: this.displayMode === 'full' ? -20 : -10,
                height: this.displayMode === 'full' ? -10 : -5,
                ellipsis: true
              }
            }
          }
        })

        // 优化连接线样式
        this.graph.addEdge({
          source: entity.id,
          target: attribute.id,
          attrs: {
            line: {
              stroke: '#000',
              strokeWidth: field.isPrimaryKey ? 2 : 1,
              targetMarker: null,
            },
          },
          connector: 'normal',
          router: {
            name: 'normal',
          },
        })
      })

      return entity
    },

    formatAttributeLabel(field) {
      const typeWithLength = this.extractTypeAndLength(field.type)
      
      if (this.displayMode === 'full') {
        return [
          field.name,
          field.comment ? `(${field.comment})` : '',
          `${typeWithLength}`
        ].filter(Boolean).join('\n')
      } else {
        return [
          field.name,
          `${typeWithLength}`
        ].join('\n')
      }
    },

    extractTypeAndLength(type) {
      // 提取类型和长度信息
      const match = type.match(/(\w+)(?:\((\d+(?:,\d+)?)\))?/)
      if (!match) return type
      
      const [, baseType, length] = match
      return length ? `${baseType}(${length})` : baseType
    },

    generateER() {
      const sql = this.sqlInput.trim()
      const tableInfo = this.parseSql(sql)
      
      if (!tableInfo) {
        this.$message.error('SQL解析失败，请检查SQL语法')
        return
      }

      // 创建表实体节点
      const tableNode = this.graph.addNode({
        shape: 'er-entity',
        x: 100,
        y: 100,
        width: 200,
        height: 40,
        label: tableInfo.tableName,
        attrs: {
          body: {
            fill: '#fff',
            stroke: '#000',
            strokeWidth: 2
          },
          label: {
            fontSize: 16,
            fontWeight: 'bold'
          }
        }
      })

      // 创建字段节点
      let y = 200
      tableInfo.columns.forEach((column, index) => {
        const label = [
          column.name,
          `(${column.type})`,
          column.comment
        ].filter(Boolean).join('\n')

        const attributeNode = this.graph.addNode({
          shape: 'er-attribute',
          x: 100 + (index % 2) * 220,
          y: y + Math.floor(index / 2) * 60,
          width: 180,
          height: 50,
          label: label,
          attrs: {
            body: {
              fill: '#fff',
              stroke: column.isPrimaryKey ? '#ff4d4f' : '#000',
              strokeWidth: column.isPrimaryKey ? 2 : 1
            },
            label: {
              fontSize: 12,
              fill: '#333'
            }
          }
        })

        // 连接表实体和字段
        this.graph.addEdge({
          source: tableNode,
          target: attributeNode,
          attrs: {
            line: {
              stroke: column.isPrimaryKey ? '#ff4d4f' : '#999',
              strokeWidth: column.isPrimaryKey ? 2 : 1
            }
          }
        })
      })

      // 自动布局
      this.applyLayout()
    },

    // 修改导出图片方法
    async exportAsImage(type) {
      try {
        // 确保画布内容完全渲染
        await this.graph.drawBackground()
        await this.graph.drawGrid()
        
        const options = {
          backgroundColor: '#ffffff',
          padding: 20,
          width: this.graph.getContentBBox().width + 40,
          height: this.graph.getContentBBox().height + 40,
        }

        if (type === 'png') {
          const blob = await this.graph.exportPNG(options)
          this.downloadBlob(blob, 'er-diagram.png')
        } else if (type === 'jpeg') {
          const blob = await this.graph.exportJPEG(options)
          this.downloadBlob(blob, 'er-diagram.jpg')
        }
      } catch (error) {
        console.error('导出图片失败:', error)
      }
    },

    // 修改导出SVG方法
    async exportAsSvg() {
      try {
        const svg = await this.graph.exportSVG()
        const blob = new Blob([svg], { type: 'image/svg+xml' })
        this.downloadBlob(blob, 'er-diagram.svg')
      } catch (error) {
        console.error('导出SVG失败:', error)
      }
    },

    // 导出JSON方法保持不变
    exportAsJson() {
      const json = this.graph.toJSON()
      const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' })
      this.downloadBlob(blob, 'er-diagram.json')
    },

    // 统一的下载方法
    downloadBlob(blob, fileName) {
      const url = URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.download = fileName
      link.href = url
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      URL.revokeObjectURL(url)
    },

    // 更新图形样式
    updateShapeStyle() {
      const nodes = this.graph.getNodes()
      nodes.forEach(node => {
        node.attr('body/fill', this.shapeColor)
      })
    },

    // 更新线条样式
    updateLineStyle() {
      const edges = this.graph.getEdges()
      edges.forEach(edge => {
        edge.attr('line/stroke', this.lineColor)
      })
    },

    // 应用布局
    applyLayout() {
      const nodes = this.graph.getNodes()
      const edges = this.graph.getEdges()
      
      if (nodes.length === 0) return

      switch (this.layoutType) {
        case 'classic':
          this.applyClassicLayout()
          break
        case 'tree':
          this.applyTreeLayout()
          break
        case 'radial':
          this.applyRadialLayout()
          break
      }
    },

    // 经典布局（使用 Dagre）
    applyClassicLayout() {
      const layout = new DagreLayout({
        type: 'dagre',
        rankdir: 'TB',
        align: 'UL',
        ranksep: 50,
        nodesep: 50,
        controlPoints: true,
      })

      const nodes = this.graph.getNodes()
      const edges = this.graph.getEdges()

      const model = {
        nodes: nodes.map(node => ({
          id: node.id,
          width: node.size().width,
          height: node.size().height,
        })),
        edges: edges.map(edge => ({
          source: edge.getSourceCellId(),
          target: edge.getTargetCellId(),
        })),
      }

      const positions = layout.layout(model)
      
      positions.nodes.forEach(node => {
        const graphNode = this.graph.getCellById(node.id)
        if (graphNode) {
          graphNode.position(node.x, node.y)
        }
      })
    },

    // 树状布局
    applyTreeLayout() {
      const layout = new DagreLayout({
        type: 'dagre',
        rankdir: 'TB',
        align: 'DL',
        ranksep: 80,
        nodesep: 60,
        controlPoints: true,
      })

      // 类似经典布局的实现，但调整了间距和方向
      this.applyLayoutWithConfig(layout)
    },

    // 星芒布局
    applyRadialLayout() {
      const nodes = this.graph.getNodes()
      const center = {
        x: this.graph.getContentBBox().width / 2,
        y: this.graph.getContentBBox().height / 2,
      }
      
      const radius = Math.min(300, Math.max(150, nodes.length * 30))
      const angleStep = (2 * Math.PI) / nodes.length

      nodes.forEach((node, index) => {
        const angle = angleStep * index
        const x = center.x + radius * Math.cos(angle)
        const y = center.y + radius * Math.sin(angle)
        node.position(x, y)
      })
    },

    // 自动布局
    autoLayout() {
      this.applyLayout()
      this.graph.zoomToFit({ padding: 50 })
      this.graph.centerContent()
    },

    // 更新选中图形的样式
    updateSelectionStyle() {
      this.selectedCells.forEach(cell => {
        if (cell.isNode()) {
          cell.attr({
            body: {
              stroke: '#1890ff',
              strokeWidth: 2,
            },
          })
        } else if (cell.isEdge()) {
          cell.attr({
            line: {
              stroke: '#1890ff',
              strokeWidth: 2,
            },
          })
        }
      })
    },

    // 开始编辑文本
    startEditing(cell, e) {
      if (this.isEditing) return

      this.isEditing = true

      // 创建编辑框
      const textBox = document.createElement('div')
      textBox.className = 'node-text-editor'
      
      // 获取节点位置和大小
      const bbox = cell.getBBox()
      const scale = this.graph.scale()
      
      // 设置编辑框样式和位置
      Object.assign(textBox.style, {
        position: 'absolute',
        left: `${bbox.x * scale.sx}px`,
        top: `${bbox.y * scale.sy}px`,
        width: `${bbox.width * scale.sx}px`,
        height: `${bbox.height * scale.sy}px`,
        zIndex: 999,
        background: '#fff',
        border: '2px solid #1890ff',
        borderRadius: '4px',
        padding: '4px',
        outline: 'none',
        boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
      })

      // 设置编辑框内容
      textBox.contentEditable = 'true'
      textBox.innerText = cell.attr('label/text') || ''

      // 添加到画布容器
      this.graph.container.appendChild(textBox)
      textBox.focus()

      // 选中所有文本
      const range = document.createRange()
      range.selectNodeContents(textBox)
      const selection = window.getSelection()
      selection.removeAllRanges()
      selection.addRange(range)

      // 处理编辑完成
      const finishEditing = () => {
        const text = textBox.innerText.trim()
        if (text) {
          cell.attr('label/text', text)
        }
        textBox.remove()
        this.isEditing = false
      }

      // 监听事件
      textBox.addEventListener('blur', finishEditing)
      textBox.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
          e.preventDefault()
          finishEditing()
        }
        if (e.key === 'Escape') {
          textBox.remove()
          this.isEditing = false
        }
      })
    },

    // 处理键盘删除事件
    handleKeyDown(e) {
      // 确保不在输入状态
      if ((e.key === 'Delete' || e.key === 'Backspace') &&
          document.activeElement.tagName !== 'INPUT' &&
          document.activeElement.tagName !== 'TEXTAREA' &&
          !document.activeElement.hasAttribute('contenteditable')) {
        const selectedCells = this.graph.getSelectedCells()
        if (selectedCells.length > 0) {
          e.preventDefault()
          // 删除选中的节点及其关联的边
          selectedCells.forEach(cell => {
            if (cell.isNode()) {
              // 获取与节点相连的所有边
              const connectedEdges = this.graph.getConnectedEdges(cell)
              // 先删除边
              connectedEdges.forEach(edge => this.graph.removeCell(edge))
              // 再删除节点
              this.graph.removeCell(cell)
            }
          })
          // 更新画布
          this.graph.cleanSelection()
        }
      }
    },

    // 清理图形
    clearGraph() {
      if (this.graph) {
        this.graph.clearCells()
        this.graph.clearSelection()
      }
    },

    watch: {
      displayMode() {
        // 当显示模式改变时重新生成图表
        if (this.sqlInput) {
          this.generateER()
        }
      }
    }
  },
  beforeDestroy() {
    if (this.graph) {
      this.graph.dispose()
    }
    // 移除键盘事件监听
    window.removeEventListener('keydown', this.handleKeyDown)
  }
}
</script>

<style scoped>
.er-tools {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: #f0f2f5;
}

/* 公告栏样式 */
.announcement-bar {
  height: 40px;
  background: #f0f7ff;
  border-bottom: 1px solid #e8e8e8;
  display: flex;
  align-items: center;
  padding: 8px 16px;
  overflow: hidden;
}

.announcement-bar i {
  font-size: 18px;
  color: #1890ff;
  margin-right: 12px;
}

.announcement-content {
  flex: 1;
  overflow: hidden;
  position: relative;
}

.scroll-text {
  display: inline-block;
  white-space: nowrap;
  animation: scrollText 20s linear infinite;
}

@keyframes scrollText {
  0% {
    transform: translateX(100%);
  }
  100% {
    transform: translateX(-100%);
  }
}

/* 主容器样式 */
.main-container {
  flex: 1;
  display: flex;
  padding: 16px;
  gap: 16px;
  min-height: 0; /* 重要：防止内容溢出 */
}

/* 左侧面板样式 */
.left-panel {
  width: 260px;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow-y: auto;
  height: calc(100vh - 120px); /* 减去公告栏和版权栏的高度 */
}

.style-control,
.layout-control {
  margin-bottom: 20px;
  padding: 12px;
  border-bottom: 1px solid #e8e8e8;
}

.style-options,
.layout-options {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 8px;
}

.color-picker {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.color-picker input[type="color"] {
  width: 40px;
  height: 24px;
  padding: 0;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  cursor: pointer;
}

.layout-options {
  gap: 8px;
}

.layout-options .el-select {
  width: 100%;
}

.layout-options .el-button {
  margin-top: 8px;
}

.display-mode {
  margin-bottom: 20px;
  padding: 12px;
  border-bottom: 1px solid #e8e8e8;
}

.mode-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.mode-options label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.tools-section {
  margin-bottom: 20px;
}

.shapes-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  padding: 8px;
}

.shape-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8px;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
  cursor: move;
}

.shape-item:hover {
  background: #f5f5f5;
}

.shape-preview {
  width: 40px;
  height: 40px;
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.shape-preview.er-entity {
  border: 2px solid #000;
}

.shape-preview.er-attribute {
  border: 1px solid #000;
  border-radius: 50%;
}

.shape-preview.er-key-attribute {
  border: 2px solid #000;
  border-radius: 50%;
}

.shape-preview.er-relationship {
  transform: rotate(45deg);
  border: 1px solid #000;
}

.sql-input {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.sql-input textarea {
  flex: 1;
  margin: 16px 0;
  padding: 8px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  resize: none;
  font-family: monospace;
}

.generate-btn {
  padding: 8px 16px;
  background: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.generate-btn:hover {
  background: #40a9ff;
}

/* 画布容器样式 */
.canvas-container {
  flex: 1;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow: auto;
  height: calc(100vh - 120px); /* 减去公告栏和版权栏的高度 */
}

/* 右侧面板样式 */
.right-panel {
  width: 200px;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow-y: auto;
  height: calc(100vh - 120px); /* 减去公告栏和版权栏的高度 */
}

.export-options {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 16px;
}

.export-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: #fff;
  border: 1px solid #1890ff;
  color: #1890ff;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s;
}

.export-btn:hover {
  background: #1890ff;
  color: #fff;
}

.export-btn i {
  font-size: 16px;
}

/* 版权栏样式 */
.copyright-bar {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  background: #fff;
  border-top: 1px solid #e8e8e8;
  margin-top: auto; /* 确保版权栏在底部 */
}

.copyright-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

.logo {
  color: #1890ff;
  font-weight: bold;
  font-size: 14px;
}

.version {
  background: #f0f2f5;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 12px;
  color: #666;
}

.copyright-center {
  color: #666;
  font-size: 12px;
}

.copyright-right {
  display: flex;
  gap: 20px;
}

.copyright-right a {
  color: #666;
  font-size: 12px;
  text-decoration: none;
  transition: color 0.2s;
}

.copyright-right a:hover {
  color: #1890ff;
}

/* 确保所有面板内容都有适当的内边距 */
.left-panel,
.right-panel {
  padding: 16px;
}

/* 滚动条美化 */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-thumb {
  background: #ccc;
  border-radius: 3px;
}

::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

/* 编辑框样式 */
:deep(.node-text-editor) {
  font-family: inherit;
  font-size: 14px;
  line-height: 1.5;
  color: #333;
  background: #fff;
  border: 2px solid #1890ff;
  border-radius: 4px;
  padding: 4px;
  min-width: 50px;
  min-height: 20px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
  outline: none;
  resize: none;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

/* 选中状态样式 */
:deep(.x6-node-selected) {
  outline: none !important;
}

:deep(.x6-node-selected rect) {
  stroke: #1890ff !important;
  stroke-width: 1px !important;
}

:deep(.x6-edge-selected) path {
  stroke: #1890ff !important;
  stroke-width: 2px !important;
}

.style-control {
  padding: 16px;
  border-bottom: 1px solid #e8e8e8;
}

.style-control h3 {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: #333;
}

.el-radio-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.el-radio {
  margin-right: 0;
}

:deep(.x6-node-tool-resize) {
  /* 调整大小手柄样式 */
  & circle {
    fill: #fff;
    stroke: #1890ff;
    stroke-width: 1;
    r: 4;
  }

  & circle:hover {
    fill: #1890ff;
  }
}

:deep(.x6-node-tool-boundary) {
  pointer-events: none;
}
</style>